/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cn.ac.iie.di.ban.nmpp.metastore;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.log4j.Logger;
import cn.ac.iie.di.ban.nmpp.config.Configuration;
import cn.ac.iie.di.ban.nmpp.handler.TableSe2DWHandler;
import cn.ac.iie.di.ban.nmpp.config.ConfigurationTablesReader;

/**
 *
 * @author ulss
 */
public class MetaStoreManager {

    private static MetaStoreManager metaStoreManager = null;
    private Map<String, TableSe2DBRule> tableSe2DBRuleSet = new HashMap<String, TableSe2DBRule>();
    private Map<String, TableSe2DWHandler> tableChangeHandler = new HashMap<String, TableSe2DWHandler>();
    Configuration conf = null;
    public static final String METASTORE_DB_NAME = "metaStoreDB";
    private static Logger logger = Logger.getLogger(MetaStoreManager.class.getName());

    private MetaStoreManager(Configuration pConf) {
        conf = pConf;
    }

    public static MetaStoreManager getMetaStoreManger(Configuration pConf) {

        if (metaStoreManager == null) {
            try {
                metaStoreManager = new MetaStoreManager(pConf);
                metaStoreManager.init();
            } catch (Exception ex) {
                metaStoreManager = null;
                logger.error("initializing metaStoreManager is failed for " + ex, ex);
            }
        }
        return metaStoreManager;
    }

    private void init() throws Exception {
        //fixme
//        initializeMetaStoreThriftClient();
//        syncTableSe2DBRuleSet();
    }

    private Map<String, TableSe2DBRule> syncTableSe2DBRuleSet() throws Exception {

        Map<String, TableSe2DBRule> newestTableSe2DBRuleSet = new HashMap<String, TableSe2DBRule>();
        int tryConnectTimes = 0;
        ArrayList<HashMap<String, String>> confGetTablesProperties = ConfigurationTablesReader.executeQuery();
        for (int i = 0; i < confGetTablesProperties.size(); i++) {
            String ruleName = confGetTablesProperties.get(i).get("rulename").trim();
            String ruleContent = confGetTablesProperties.get(i).get("rulecontent").trim();
            logger.info("tp rule name:" + ruleName + ";rule content:" + ruleContent + " sgroup " + confGetTablesProperties.get(i).get("sgroup").trim());
            String[] ruleContentItems = ruleContent.split("\\|");
            //mqName|dbType|connStrL|userName|passwd|tableName|parallelSize|batchSize|columnSetStr
            String mqName = ruleContentItems[0];
            String dbType = ruleContentItems[1];
            String connStr = ruleContentItems[2];
            String userName = ruleContentItems[3];
            String passwd = ruleContentItems[4];
            String tableName = ruleContentItems[5];
            int parallelSize = Integer.parseInt(ruleContentItems[6]);
            int batchSize = Integer.parseInt(ruleContentItems[7]);
            String sGroup = confGetTablesProperties.get(i).get("sgroup").trim();
            TableSe2DBRule tableSe2DBRule = new TableSe2DBRule(ruleName, ruleContent, mqName, dbType, connStr, userName, passwd, tableName, parallelSize, batchSize, sGroup);
            newestTableSe2DBRuleSet.put(ruleName, tableSe2DBRule);
        }
        return newestTableSe2DBRuleSet;
    }

    public void removeTableSe2DBRule(TableSe2DBRule pTableSe2DBRule) {
        tableSe2DBRuleSet.remove(pTableSe2DBRule.getRuleName());
    }

    public Map<String, List> getTableSe2DBRuleSet() throws Exception {
        Map<String, TableSe2DBRule> newestTableSe2DBRuleSet = syncTableSe2DBRuleSet();
        List<TableSe2DBRule> newTableSe2DBRuleList = new ArrayList<TableSe2DBRule>();
        List<TableSe2DBRule> updatedTableSe2DBRuleList = new ArrayList<TableSe2DBRule>();
        List<TableSe2DBRule> deletedTableSe2DBRuleList = new ArrayList<TableSe2DBRule>();

        //get deleted rules
        Iterator existTableSe2DBRuleItor = tableSe2DBRuleSet.entrySet().iterator();
        while (existTableSe2DBRuleItor.hasNext()) {
            TableSe2DBRule existTableSe2DBRule = ((Entry<String, TableSe2DBRule>) existTableSe2DBRuleItor.next()).getValue();
            if (!newestTableSe2DBRuleSet.containsKey(existTableSe2DBRule.ruleName)) {
                existTableSe2DBRuleItor.remove();//delete from tableSe2DBRuleSet
                deletedTableSe2DBRuleList.add(existTableSe2DBRule);
            }
        }

        //get new rules and updated rules
        Iterator newestTableSe2DBRuleItor = newestTableSe2DBRuleSet.entrySet().iterator();
        while (newestTableSe2DBRuleItor.hasNext()) {
            TableSe2DBRule newestTableSe2DBRule = ((Entry<String, TableSe2DBRule>) newestTableSe2DBRuleItor.next()).getValue();
            TableSe2DBRule tmpTableSe2DBRule = tableSe2DBRuleSet.get(newestTableSe2DBRule.ruleName);
            if (tmpTableSe2DBRule == null) {
                tableSe2DBRuleSet.put(newestTableSe2DBRule.ruleName, newestTableSe2DBRule);
                newTableSe2DBRuleList.add(newestTableSe2DBRule);
            } else {
                if (!newestTableSe2DBRule.ruleContent.equals(tmpTableSe2DBRule.ruleContent)) {
                    tableSe2DBRuleSet.put(newestTableSe2DBRule.ruleName, newestTableSe2DBRule);
                    updatedTableSe2DBRuleList.add(newestTableSe2DBRule);
                }
            }
        }

        Map<String, List> tablePersistanceRuleOPSet = new HashMap<String, List>();
        tablePersistanceRuleOPSet.put("new", newTableSe2DBRuleList);
        tablePersistanceRuleOPSet.put("updated", updatedTableSe2DBRuleList);
        tablePersistanceRuleOPSet.put("deleted", deletedTableSe2DBRuleList);
        return tablePersistanceRuleOPSet;
    }

    public TableSe2DBRule getTableSe2DBRule(String pTableName) {
        return tableSe2DBRuleSet.get(pTableName);
    }

    public void registerHandler(TableSe2DWHandler pTableSe2DBHandler) {
        tableChangeHandler.put(pTableSe2DBHandler.getRuleName(), pTableSe2DBHandler);
    }

    public void removeHandler(TableSe2DWHandler pTableSe2DBHandler) {
        tableChangeHandler.remove(pTableSe2DBHandler.getRuleName());
    }

    private void act2TableChange() {
    }
}
